﻿//===============================================================================
// Microsoft Innovation Centre - Western Europe
// Copyright (c) 2008 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Microsoft.WVB.Framework;
using Microsoft.WVB.Silverlight.Infrastructure;

namespace Microsoft.WVB.UI
{
    [TemplateVisualState(Name = VisualStates.StateFormDisplayed, GroupName = VisualStates.GroupCommon),
    TemplateVisualState(Name = VisualStates.StateFormNotified, GroupName = VisualStates.GroupCommon),
    TemplateVisualState(Name = VisualStates.StateFormSubmitted, GroupName = VisualStates.GroupCommon)]
    [TemplatePart(Name = FormPrimitive.ElementInteractiveName, Type = typeof(ContentControl)),
    TemplatePart(Name = FormPrimitive.ElementWaitName, Type = typeof(ContentControl)),
    TemplatePart(Name = FormPrimitive.ElementNotifyName, Type = typeof(ContentControl)),
    TemplatePart(Name = FormPrimitive.ButtonSubmitName, Type = typeof(Button)),
    TemplatePart(Name = FormPrimitive.ButtonCancelName, Type = typeof(Button)),
    TemplatePart(Name = FormPrimitive.ButtonResetName, Type = typeof(Button))]
    public abstract class FormPrimitive : Control
    {
        private const string ElementInteractiveName = "ElementInteractive";
        private const string ElementWaitName = "ElementWait";
        private const string ElementNotifyName = "ElementNotify";
        private const string ButtonSubmitName = "SubmitButton";
        private const string ButtonCancelName = "CancelButton";
        private const string ButtonResetName = "ResetButton";

        private RoutedEventHandler submitEventHandler = null;
        private RoutedEventHandler cancelEventHandler = null;
        private RoutedEventHandler resetEventHandler = null;

        public IUserManager ViewModel { get; set; }

        public DataTemplate InteractiveTemplate
        {
            get { return (DataTemplate)GetValue(InteractiveTemplateProperty); }
            set { SetValue(InteractiveTemplateProperty, value); }
        }
        public static readonly DependencyProperty InteractiveTemplateProperty = null;

        public DataTemplate WaitTemplate
        {
            get { return (DataTemplate)GetValue(WaitTemplateProperty); }
            set { SetValue(WaitTemplateProperty, value); }
        }
        public static readonly DependencyProperty WaitTemplateProperty = null;

        public DataTemplate NotifyTemplate
        {
            get { return (DataTemplate)GetValue(NotifyTemplateProperty); }
            set { SetValue(NotifyTemplateProperty, value); }
        }
        public static readonly DependencyProperty NotifyTemplateProperty = null;

        public UserManagerState CurrentState
        {
            get { return (UserManagerState)GetValue(CurrentStateProperty); }
            set { SetValue(CurrentStateProperty, value); }
        }
        public static readonly DependencyProperty CurrentStateProperty = null;

        public object InteractiveContent
        {
            get { return (object)GetValue(InteractiveContentProperty); }
            set { SetValue(InteractiveContentProperty, value); }
        }
        public static readonly DependencyProperty InteractiveContentProperty = null;

        public object WaitContent
        {
            get { return (object)GetValue(WaitContentProperty); }
            set { SetValue(WaitContentProperty, value); }
        }
        public static readonly DependencyProperty WaitContentProperty = null;

        public object NotifyContent
        {
            get { return (object)GetValue(NotifyContentProperty); }
            set { SetValue(NotifyContentProperty, value); }
        }
        public static readonly DependencyProperty NotifyContentProperty = null;

        private ContentControl ElementInteractive { get; set; }
        private ContentControl ElementWait { get; set; }
        private ContentControl ElementNotify { get; set; }
        protected Button ButtonSubmit { get; set; }
        protected Button ButtonCancel { get; set; }
        protected Button ButtonReset { get; set; }

        static FormPrimitive()
        {
            CurrentStateProperty = DependencyProperty.Register("CurrentState", typeof(UserManagerState), typeof(FormPrimitive), new PropertyMetadata(FormPrimitive.OnCurrentStateChanged));

            InteractiveTemplateProperty = DependencyProperty.Register("InteractiveTemplate", typeof(DataTemplate), typeof(FormPrimitive), new PropertyMetadata(new PropertyChangedCallback(FormPrimitive.OnInteractiveTemplateChanged)));
            WaitTemplateProperty = DependencyProperty.Register("WaitTemplate", typeof(DataTemplate), typeof(FormPrimitive), new PropertyMetadata(new PropertyChangedCallback(FormPrimitive.OnWaitTemplateChanged)));
            NotifyTemplateProperty = DependencyProperty.Register("NotifyTemplate", typeof(DataTemplate), typeof(FormPrimitive), new PropertyMetadata(new PropertyChangedCallback(FormPrimitive.OnNotifyTemplateChanged)));

            InteractiveContentProperty = DependencyProperty.Register("InteractiveContent", typeof(object), typeof(FormPrimitive), new PropertyMetadata(new PropertyChangedCallback(FormPrimitive.OnInteractiveContentChanged)));
            WaitContentProperty = DependencyProperty.Register("WaitContent", typeof(object), typeof(FormPrimitive), new PropertyMetadata(new PropertyChangedCallback(FormPrimitive.OnWaitContentChanged)));
            NotifyContentProperty = DependencyProperty.Register("NotifyContent", typeof(object), typeof(FormPrimitive), new PropertyMetadata(new PropertyChangedCallback(FormPrimitive.OnNotifyContentChanged)));
        }

        public FormPrimitive()
        {
            if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
            {
                ViewModel = IoC.GetCreate<IUserManager>();
                DataContext = ViewModel;
            }    
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            this.ElementInteractive = base.GetTemplateChild(FormPrimitive.ElementInteractiveName) as ContentControl;
            this.ElementNotify = base.GetTemplateChild(FormPrimitive.ElementNotifyName) as ContentControl;
            this.ElementWait = base.GetTemplateChild(FormPrimitive.ElementWaitName) as ContentControl;
            this.ButtonCancel = base.GetTemplateChild(FormPrimitive.ButtonCancelName) as Button;
            this.ButtonSubmit = base.GetTemplateChild(FormPrimitive.ButtonSubmitName) as Button;
            this.ButtonReset = base.GetTemplateChild(FormPrimitive.ButtonResetName) as Button;

            if (ButtonSubmit != null)
            {
                if (submitEventHandler == null)
                {
                    submitEventHandler = delegate(object sender, RoutedEventArgs e)
                    {
                        OnButtonSubmitClicked(sender as Button);
                    };
                }
                ButtonSubmit.Click += submitEventHandler;
            }

            if (ButtonCancel != null)
            {
                if (cancelEventHandler == null)
                {
                    cancelEventHandler = delegate(object sender, RoutedEventArgs e)
                    {
                        OnButtonCancelClicked(sender as Button);
                    };
                }
                ButtonCancel.Click += cancelEventHandler;
            }

            if (ButtonReset != null)
            {
                if (resetEventHandler == null)
                {
                    resetEventHandler = delegate(object sender, RoutedEventArgs e)
                    {
                        OnButtonResetClicked(sender as Button);
                    };
                }
                ButtonReset.Click += resetEventHandler;
            }


            if (this.ElementInteractive != null)
            {
                if (this.InteractiveTemplate != null)
                {
                    this.OnInteractiveTemplateChanged(null, this.InteractiveTemplate);
                }
                else
                {
                    this.OnInteractContentChanged(null, this.InteractiveContent);
                }
            }

            if (this.ElementNotify != null)
            {
                if (this.NotifyTemplate != null)
                {
                    this.OnNotifyTemplateChanged(null, this.NotifyTemplate);
                }
                else
                {
                    this.OnNotifyContentChanged(null, this.NotifyContent);
                }
            }

            if (this.ElementWait != null)
            {
                if (this.WaitTemplate != null)
                {
                    this.OnWaitTemplateChanged(null, this.WaitTemplate);
                }
                else
                {
                    this.OnWaitContentChanged(null, this.WaitContent);
                }
            }

            Binding b = new Binding("UserState");
            b.Source = ViewModel;
            b.Mode = BindingMode.OneWay;

            this.SetBinding(CurrentStateProperty, b);

            UpdateVisualState();
        }

        protected abstract void OnButtonResetClicked(Button resetButton);
        protected abstract void OnButtonCancelClicked(Button cancelButton);
        protected abstract void OnButtonSubmitClicked(Button submitButton);

        private static void OnInteractiveContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((FormPrimitive)d).OnInteractContentChanged(e.OldValue, e.NewValue);
        }

        private static void OnWaitContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((FormPrimitive)d).OnWaitContentChanged(e.OldValue, e.NewValue);
        }

        private static void OnNotifyContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((FormPrimitive)d).OnNotifyContentChanged(e.OldValue, e.NewValue);
        }

        private static void OnCurrentStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((FormPrimitive)d).OnCurrentStateChanged((UserManagerState)e.OldValue, (UserManagerState)e.NewValue);
        }

        private static void OnInteractiveTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((FormPrimitive)d).OnInteractiveTemplateChanged((DataTemplate)e.OldValue, (DataTemplate)e.NewValue);
        }

        private static void OnWaitTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((FormPrimitive)d).OnWaitTemplateChanged((DataTemplate)e.OldValue, (DataTemplate)e.NewValue);
        }

        private static void OnNotifyTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((FormPrimitive)d).OnNotifyTemplateChanged((DataTemplate)e.OldValue, (DataTemplate)e.NewValue);
        }

        protected virtual void OnInteractiveTemplateChanged(DataTemplate oldValue, DataTemplate newValue)
        {
            if (this.ElementInteractive != null)
            {
                if (InteractiveTemplate == null)
                {
                    this.ElementInteractive.Content = this.InteractiveContent;
                }
                else
                {
                    FrameworkElement element = this.InteractiveTemplate.LoadContent() as FrameworkElement;
                    this.ElementInteractive.Content = element;
                }
            }
        }

        protected virtual void OnWaitTemplateChanged(DataTemplate oldValue, DataTemplate newValue)
        {
            if (this.ElementWait != null)
            {
                if (WaitTemplate == null)
                {
                    this.ElementWait.Content = this.WaitContent;
                }
                else
                {
                    FrameworkElement element = this.WaitTemplate.LoadContent() as FrameworkElement;
                    this.ElementWait.Content = element;
                }
            }
        }

        protected virtual void OnNotifyTemplateChanged(DataTemplate oldValue, DataTemplate newValue)
        {
            if (this.ElementNotify != null)
            {
                if (NotifyTemplate == null)
                {
                    this.ElementNotify.Content = this.NotifyContent;
                }
                else
                {
                    FrameworkElement element = this.NotifyTemplate.LoadContent() as FrameworkElement;
                    this.ElementNotify.Content = element;
                }
            }
        }

        protected virtual void OnInteractContentChanged(object oldValue, object newValue)
        {
            if ((InteractiveTemplate == null) && (this.ElementInteractive != null))
            {
                this.ElementInteractive.Content = newValue;
            }
        }

        protected virtual void OnWaitContentChanged(object oldValue, object newValue)
        {
            if ((WaitTemplate == null) && (this.ElementWait != null))
            {
                this.ElementWait.Content = newValue;
            }
        }

        protected virtual void OnNotifyContentChanged(object oldValue, object newValue)
        {
            if ((NotifyTemplate == null) && (this.ElementNotify != null))
            {
                this.ElementNotify.Content = newValue;
            }
        }

        protected virtual void OnCurrentStateChanged(UserManagerState oldValue, UserManagerState newValue)
        {
            this.UpdateVisualState();
        }

        internal void UpdateVisualState()
        {
            this.ChangeVisualState(true);
        }

        protected virtual void ChangeVisualState(bool useTransitions)
        {
            if (this.CurrentState == UserManagerState.UnSigned)
            {
                VisualStates.GoToState(this, useTransitions, new String[] { VisualStates.StateFormDisplayed });
            }

            if ((this.CurrentState == UserManagerState.SigningIn) || (this.CurrentState == UserManagerState.SigningUp))
            {
                VisualStates.GoToState(this, useTransitions, new String[] { VisualStates.StateFormSubmitted });
            }

            if ((this.CurrentState == UserManagerState.Signed) || (this.CurrentState == UserManagerState.Failed))
            {
                VisualStates.GoToState(this, useTransitions, new String[] { VisualStates.StateFormNotified });
            }
        }
    }
}
